package tu_rang

import (
	"device-modbus/core"
	"device-modbus/internal/biz/model"
	"encoding/binary"
	"fmt"
	"time"

	"github.com/cloudwego/hertz/pkg/common/hlog"
)

// ZTSSoilFourParamProtocol 兆泰盛五插针土壤四参数传感器协议实现（仅支持数据询问与解析）
// 型号：ZTS-3001-TR-*-N01，适配询问指令06 03 00 00 00 04 45 BE与应答06 03 08 01 CB 00 D9 00 43 00 51 19 58
type ZTSSoilFourParamProtocol struct{}

// NewProtocol 导出插件创建函数（符合core.ProtocolCreator签名，供管理器加载）
func NewProtocol() core.SensorProtocol {
	return &ZTSSoilFourParamProtocol{}
}

// GetType 返回传感器类型标识（手册定义为土壤四参数，标识为"modbus"）
func (p *ZTSSoilFourParamProtocol) GetType() string {
	return "modbus"
}

// GetModel 返回传感器准确型号（手册明确型号：ZTS-3001-TR-*-N01）
func (p *ZTSSoilFourParamProtocol) GetModel() string {
	return "土壤"
}

// GetProtocolName 返回协议唯一标识（结合型号与Modbus-RTU协议，全局唯一）
func (p *ZTSSoilFourParamProtocol) GetProtocolName() string {
	return "土壤"
}

// ZTSSoilQueryData 传感器解析后的数据结构（仅含查询相关字段，匹配手册7.2节寄存器定义）
type ZTSSoilQueryData struct {
	DeviceAddr   byte    // 设备地址（指令中为0x06，手册支持1~254）
	FuncCode     byte    // 功能码（固定0x03，读取寄存器）
	ValidBytes   byte    // 有效字节数（查询四参数时固定0x08）
	Moisture     float64 // 含水率（%，寄存器0000H值÷10）
	Temperature  float64 // 温度（℃，寄存器0001H值÷10）
	Conductivity float64 // 电导率（μS/cm，寄存器0002H直接取值）
	PH           float64 // PH值（寄存器0003H值÷10）
}

// 指令与应答相关常量（匹配给定指令与手册规范）
const (
	TargetDeviceAddr = 0x06   // 目标设备地址（与询问指令06对应）
	QueryFuncCode    = 0x03   // 询问功能码（固定0x03，读取寄存器）
	QueryStartAddr   = 0x0000 // 询问起始寄存器（与指令00 00对应）
	QueryRegCount    = 0x0004 // 询问寄存器数量（与指令00 04对应，读取4个参数）
	QueryRespLen     = 13     // 询问应答帧长度（与给定应答13字节匹配）
	QueryValidBytes  = 0x08   // 询问应答有效字节数（与给定应答08对应）
)

// BuildRequest 构建指定询问指令（06 03 00 00 00 04 45 BE），仅支持数据询问
func (p *ZTSSoilFourParamProtocol) BuildRequest(deviceAddr, funcCode byte, startAddr, dataLength uint16) ([]byte, error) {
	// 1. 严格校验询问参数（必须匹配给定指令与手册规范）
	if deviceAddr != TargetDeviceAddr {
		return nil, fmt.Errorf("%w: 设备地址必须为0x%02X（与询问指令06对应），实际0x%02X",
			core.ErrorInvalidResponse, TargetDeviceAddr, deviceAddr)
	}
	if funcCode != QueryFuncCode {
		return nil, fmt.Errorf("%w: 仅支持功能码0x%02X（数据询问），实际0x%02X",
			core.ErrorInvalidResponse, QueryFuncCode, funcCode)
	}
	if startAddr != QueryStartAddr {
		return nil, fmt.Errorf("%w: 起始寄存器必须为0x%04X（与指令00 00对应），实际0x%04X",
			core.ErrorInvalidResponse, QueryStartAddr, startAddr)
	}
	if dataLength != QueryRegCount {
		return nil, fmt.Errorf("%w: 寄存器数量必须为0x%04X（与指令00 04对应），实际0x%04X",
			core.ErrorInvalidResponse, QueryRegCount, dataLength)
	}

	// 2. 构建帧主体（匹配指令格式：地址+功能码+起始地址+寄存器数量）
	hlog.Debugf("构建土壤四参数询问指令 | 设备地址:0x%02X, 功能码:0x%02X, 起始寄存器:0x%04X, 寄存器数量:0x%04X",
		deviceAddr, funcCode, startAddr, dataLength)
	frame := make([]byte, 6)
	frame[0] = deviceAddr                              // 0x06（指令中的06）
	frame[1] = funcCode                                // 0x03（指令中的03）
	binary.BigEndian.PutUint16(frame[2:4], startAddr)  // 0x0000（指令中的00 00）
	binary.BigEndian.PutUint16(frame[4:6], dataLength) // 0x0004（指令中的00 04）

	// 3. 计算CRC16校验（匹配指令中的45 BE，手册多项式0xA001）
	crc := calculateCRC(frame)
	frame = append(frame, byte(crc&0xFF))    // CRC低字节0x45（指令中的45）
	frame = append(frame, byte(crc>>8&0xFF)) // CRC高字节0xBE（指令中的BE）

	// 校验生成指令是否与给定指令一致
	finalCmd := fmt.Sprintf("%X", frame)
	if finalCmd != "06030000000445BE" {
		return nil, fmt.Errorf("%w: 生成指令与预期不符，预期06030000000445BE，实际%s",
			core.ErrorInvalidResponse, finalCmd)
	}
	hlog.Debugf("生成询问指令成功：%X", frame)
	return frame, nil
}

// ParseResponse 解析指定应答（06 03 08 01 CB 00 D9 00 43 00 51 19 58），仅支持数据解析
func (p *ZTSSoilFourParamProtocol) ParseResponse(resp []byte) (*model.SensorData, error) {
	// 1. 校验应答帧基础格式（匹配给定应答与手册规范）
	// 帧长度校验（必须13字节）
	if len(resp) != QueryRespLen {
		return nil, fmt.Errorf("%w: 应答帧长度应为%d字节（与给定应答一致），实际%d字节",
			core.ErrorInvalidResponse, QueryRespLen, len(resp))
	}
	// 设备地址校验（必须为0x06，与询问指令对应）
	if resp[0] != TargetDeviceAddr {
		return nil, fmt.Errorf("%w: 应答设备地址应为0x%02X（与询问指令06对应），实际0x%02X",
			core.ErrorInvalidResponse, TargetDeviceAddr, resp[0])
	}
	// 功能码校验（必须为0x03，与询问功能码对应）
	if resp[1] != QueryFuncCode {
		return nil, fmt.Errorf("%w: 应答功能码应为0x%02X（与询问功能码对应），实际0x%02X",
			core.ErrorInvalidResponse, QueryFuncCode, resp[1])
	}
	// 有效字节数校验（必须为0x08，与给定应答08对应）
	if resp[2] != QueryValidBytes {
		return nil, fmt.Errorf("%w: 应答有效字节数应为0x%02X（与给定应答08对应），实际0x%02X",
			core.ErrorInvalidResponse, QueryValidBytes, resp[2])
	}

	// 2. CRC校验（校验给定应答的19 58，手册多项式0xA001）
	crcCheckData := resp[:len(resp)-2] // 应答前11字节：06 03 08 01 CB 00 D9 00 43 00 51
	expectedCRC := calculateCRC(crcCheckData)
	actualCRC := uint16(resp[11]) | uint16(resp[12])<<8 // 应答CRC：19 58 → 0x5819
	if actualCRC != expectedCRC {
		return nil, fmt.Errorf("%w: CRC校验失败 | 预期0x%04X（与给定应答19 58对应），实际0x%04X",
			core.ErrorInvalidResponse, expectedCRC, actualCRC)
	}
	//0683088800021e000001e1e79b
	// 3. 解析数据区（给定应答数据区：01 CB 00 D9 00 43 00 51，按手册7.2节规则换算）
	dataArea := resp[3:11]
	parsed := &ZTSSoilQueryData{
		DeviceAddr: resp[0],
		FuncCode:   resp[1],
		ValidBytes: resp[2],
		// 含水率：寄存器0000H（01 CB=459）→ 459÷10=45.9%（手册规则：含水率值扩大10倍）
		Moisture: float64(binary.BigEndian.Uint16(dataArea[0:2])) / 10.0,
		// 温度：寄存器0001H（00 D9=217）→ 217÷10=21.7℃（手册规则：温度值扩大10倍，正温无需补码）
		Temperature: float64(binary.BigEndian.Uint16(dataArea[2:4])) / 10.0,
		// 电导率：寄存器0002H（00 43=67）→ 67μS/cm（手册规则：电导率直接取寄存器值）
		Conductivity: float64(binary.BigEndian.Uint16(dataArea[4:6])),
		// PH值：寄存器0003H（00 51=81）→ 81÷10=8.1（手册规则：PH值扩大10倍）
		PH: float64(binary.BigEndian.Uint16(dataArea[6:8])) / 10.0,
	}

	// 4. 输出解析日志（匹配给定应答的解析结果）
	hlog.Debugf("解析土壤四参数成功 | 设备地址:0x%02X, 含水率:%.1f%%, 温度:%.1f℃, 电导率:%.0fμS/cm, PH:%.1f",
		parsed.DeviceAddr, parsed.Moisture, parsed.Temperature, parsed.Conductivity, parsed.PH)

	// 5. 封装为全局统一SensorData结构
	return &model.SensorData{
		SensorID:  fmt.Sprintf("%d-%s", parsed.DeviceAddr, p.GetType()), // 唯一ID：6-zts_soil_four_param
		Type:      p.GetType(),
		Model:     p.GetModel(),
		Timestamp: time.Now().UnixMilli(),
		RawData:   resp, // 原始应答：06 03 08 01 CB 00 D9 00 43 00 51 19 58
		Values: map[string]string{
			"moisture":     fmt.Sprintf("%.1f", parsed.Moisture),     // 含水率：45.9%
			"temperature":  fmt.Sprintf("%.1f", parsed.Temperature),  // 温度：21.7℃
			"conductivity": fmt.Sprintf("%.0f", parsed.Conductivity), // 电导率：67μS/cm
			"ph":           fmt.Sprintf("%.1f", parsed.PH),           // PH值：8.10
		},
		Protocol: p.GetProtocolName(),
	}, nil
}

// calculateCRC 计算Modbus-RTU CRC16校验码（手册4.2节指定多项式0xA001，低位在前）
// 验证：1. 询问指令帧主体06 03 00 00 00 04 → CRC=45 BE；2. 应答前11字节06 03 08 01 CB 00 D9 00 43 00 51 → CRC=19 58
func calculateCRC(data []byte) uint16 {
	crc := uint16(0xFFFF)
	for _, b := range data {
		crc ^= uint16(b)
		for i := 0; i < 8; i++ {
			if crc&0x0001 != 0 {
				crc >>= 1
				crc ^= 0xA001 // 手册明确Modbus-RTU校验多项式
			} else {
				crc >>= 1
			}
		}
	}
	return crc
}
